﻿namespace ThreeByte.ActiveDeck.Dashboard
{
    using System.Windows.Controls;
    using System.Windows.Navigation;
    using System;
    using ActiveDeck.Dashboard.LoginUI;
    using ThreeByte.ActiveDeck.Web.Services;
    using System.ServiceModel.DomainServices.Client;
    using ThreeByte.ActiveDeck.Web.Models;
    using System.Xml.Linq;
    using System.Collections.Generic;
    using System.Text.RegularExpressions;
    using System.Linq;
    using System.IO;

    /// <summary>
    /// Home page for the application.
    /// </summary>
    public partial class Inspect : Page
    {

        public static readonly XNamespace NAMESPACE = @"http://www.activedeck.com/PowerPoint/";
        public static readonly XNamespace ns = NAMESPACE;

        /// <summary>
        /// Creates a new <see cref="Inspect"/> instance.
        /// </summary>
        public Inspect() {
            InitializeComponent();
           
        }

        /// <summary>
        /// Executes when the user navigates to this page.
        /// </summary>
        protected override void OnNavigatedTo(NavigationEventArgs e) {
            //Get the Query parameters

            string pres = null;
            string section = null;
            string page = null;

            if(this.NavigationContext.QueryString.ContainsKey("pres")){
                pres = this.NavigationContext.QueryString["pres"];
            }
            if(this.NavigationContext.QueryString.ContainsKey("section")) {
                section = this.NavigationContext.QueryString["section"];
            }
            if(this.NavigationContext.QueryString.ContainsKey("page")) {
                page = this.NavigationContext.QueryString["page"];
            }

            if(pres != null && section != null && page != null) {
                LoadPage(pres, section, page);
                LoadCurrentState(pres);
            } else if(pres != null && section != null) {
                LoadSection(pres, section);
                LoadCurrentState(pres);
            } else if(pres != null) {
                LoadPresentation(pres);
                LoadCurrentState(pres);
            } else {
                InspectorBox.Selection.Text = "Invalid navigation request";
            }
            
        }

        private void LoadCurrentState(string pres) {
            EntityQuery<PresentationState> q = ctx.GetPresentationStateQuery(pres);
            ctx.Load(q, PresentationStateLoadComplete, pres);
        }

        private void PresentationStateLoadComplete(LoadOperation<PresentationState> op) {
            if(op.HasError) {

                return;
            }

            try {
                PresentationState state = op.Entities.SingleOrDefault();

                XElement stateElement = XElement.Parse(state.SectionData);
                string section = stateElement.Attribute("Section").Value;
                CurrentStateText.Text = string.Format("Current Section: {0}", section);
                ToolTipService.SetToolTip(CurrentStateText, state.SectionData);
            } catch(Exception) {
                return; //Cannot retrieve current state
            }
        }

        private DashboardDataContext ctx = new DashboardDataContext();
        private static PresentationConfig CachedPresentationConfig;

        private void LoadPresentation(string pres) {

            //Load the Outline of the presentation
            InspectorBox.Selection.Text = string.Format("Loading Presentation {0}...", pres);

            //Always load the top-level from the webservice (un-cached)
            EntityQuery<PresentationConfig> q = ctx.GetPresentationConfigQuery(pres);
            ctx.Load(q, PresentationDataLoadComplete, pres); 

        }

        private void PresentationDataLoadComplete(LoadOperation<PresentationConfig> op) {

            //After we got the PresentationConfig, do something with it
            if(op.HasError) {
                //Handle this
                InspectorBox.Selection.Text = string.Format("Error loading presentation: {0}", op.Error.Message);
                return;
            }

            CachedPresentationConfig = op.Entities.FirstOrDefault();

            DisplayPresentation(CachedPresentationConfig);
        }

        private void DisplayPresentation(PresentationConfig config) {
            DownloadSchemaButton.IsEnabled = true;

            XElement el = XElement.Parse(config.XML);

            List<XElement> elementsToReplace = new List<XElement>();
            foreach(XElement sec in el.Elements(ns + "SlideConfig")) {
                elementsToReplace.Add(sec);
            }
            foreach(XElement sec in elementsToReplace) {
                sec.Descendants().Remove();
            }
            elementsToReplace.Clear();
            foreach(XElement res in el.Elements(ns + "Resources")) {
                elementsToReplace.Add(res);
            }
            foreach(XElement res in elementsToReplace) {
                res.Descendants().Remove();
            }

            string stringToFormat = el.ToString();

            //Replace xml entity representations in base text
            stringToFormat = stringToFormat.Replace("<", "&lt;").Replace(">", "&gt;");

            //Do a regex replace for Sections
            string regex = @"SlideConfig\s*SlideID=""(?<id>.*)""";
            string linkReplacement = string.Format(@"<Hyperlink NavigateUri=""/Inspect/{0}/${{id}}"" >$&</Hyperlink>", config.PresentationID);
            stringToFormat = Regex.Replace(stringToFormat, regex, linkReplacement);

            //Do a regex replace for ResourceList
            regex = @"Resources .*/";
            linkReplacement = string.Format(@"<Hyperlink NavigateUri=""/Resources/{0}"" >$&</Hyperlink>", config.PresentationID);
            stringToFormat = Regex.Replace(stringToFormat, regex, linkReplacement);

            //Do a regex replace for Resources
            regex = @"ResourceID=""(?<resid>.{36})"""; //Guids are always 36 characters long (including dashes)
            linkReplacement = string.Format(@"ResourceID=""<Hyperlink NavigateUri=""/Resources/{0}/${{resid}}"" >${{resid}}</Hyperlink>""", config.PresentationID);
            stringToFormat = Regex.Replace(stringToFormat, regex, linkReplacement);

            stringToFormat = string.Format("<Paragraph>{0}</Paragraph>", stringToFormat);
            stringToFormat = string.Format("<Section xml:space=\"preserve\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">{0}</Section>", stringToFormat);

            InspectorBox.Xaml = stringToFormat;
        }


        private void LoadSection(string pres, string section) {

            InspectorBox.Selection.Text = string.Format("Loading Presentation {0} Section {1}...", pres, section);

            if(CachedPresentationConfig != null && CachedPresentationConfig.PresentationID == pres) {
                //Use the cached version because it will be way quicker
                DisplaySection(CachedPresentationConfig, section);
            } else {
                //Retrieve the PresentationConfig again
                EntityQuery<PresentationConfig> q = ctx.GetPresentationConfigQuery(pres);
                ctx.Load(q, SectionDataLoadComplete, new string[] { section });
            }

        }

        private void SectionDataLoadComplete(LoadOperation<PresentationConfig> op) {

            //After we got the PresentationConfig, do something with it
            if(op.HasError) {
                //Handle this
                InspectorBox.Selection.Text = string.Format("Error loading section: {0}", op.Error.Message);
                return;
            }

            CachedPresentationConfig = op.Entities.FirstOrDefault();

            string section = ((string[])(op.UserState))[0];
            DisplaySection(CachedPresentationConfig, section);
        }

        private void DisplaySection(PresentationConfig config, string section) {
            DownloadSchemaButton.IsEnabled = true;

            XElement el = XElement.Parse(config.XML);

            XElement sec = (from p in el.Elements(ns + "SlideConfig")
                            where p.Attribute("SlideID").Value == section
                            select p).Single();

            //Find the section of interest

            List<XElement> elementsToReplace = new List<XElement>();
            foreach(XElement page in sec.Elements(ns + "Page")) {
                elementsToReplace.Add(page);
            }
            foreach(XElement page in elementsToReplace) {
                page.Descendants().Remove();
            }


            string stringToFormat = sec.ToString();

            //Replace xml entity representations in bas text
            stringToFormat = stringToFormat.Replace("<", "&lt;").Replace(">", "&gt;");

            //Do a regex replace for Pages
            string regex = @"Page\s+ID=""(?<id>\d+)""";
            string linkReplacement = string.Format(@"<Hyperlink NavigateUri=""/Inspect/{0}/{1}/${{id}}"" >$&</Hyperlink>", config.PresentationID, section);
            stringToFormat = Regex.Replace(stringToFormat, regex, linkReplacement);

            stringToFormat = string.Format("<Paragraph>{0}</Paragraph>", stringToFormat);
            stringToFormat = string.Format("<Section xml:space=\"preserve\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">{0}</Section>", stringToFormat);

            InspectorBox.Xaml = stringToFormat;
        }



        private void LoadPage(string pres, string section, string page) {

            InspectorBox.Selection.Text = string.Format("Loading Presentation {0} Section {1} Page {2}...", pres, section, page);

            if(CachedPresentationConfig != null && CachedPresentationConfig.PresentationID == pres) {
                //Use the cached version because it will be way quicker
                DisplayPage(CachedPresentationConfig, section, page);
            } else {
                //Retrieve the PresentationConfig again
                EntityQuery<PresentationConfig> q = ctx.GetPresentationConfigQuery(pres);
                ctx.Load(q, PageDataLoadComplete, new string[] { section, page });
            }

        }

        private void PageDataLoadComplete(LoadOperation<PresentationConfig> op) {

            //After we got the PresentationConfig, do something with it
            if(op.HasError) {
                //Handle this
                InspectorBox.Selection.Text = string.Format("Error loading section: {0}", op.Error.Message);
                return;
            }

            CachedPresentationConfig = op.Entities.FirstOrDefault();

            string section = ((string[])(op.UserState))[0];
            string page = ((string[])(op.UserState))[1];
            DisplayPage(CachedPresentationConfig, section, page);
        }

        private void DisplayPage(PresentationConfig config, string section, string page) {
            DownloadSchemaButton.IsEnabled = true;

            XElement el = XElement.Parse(config.XML);

            XElement sec = (from p in el.Elements(ns + "SlideConfig")
                            where p.Attribute("SlideID").Value == section
                            select p).Single();

            //Find the page of interest
            XElement pageNode = (from p in sec.Elements(ns + "Page")
                                 where p.Attribute("ID").Value == page
                                 select p).Single();



            string stringToFormat = pageNode.ToString();

            //Replace xml entity representations in bas text
            stringToFormat = stringToFormat.Replace("<", "&lt;").Replace(">", "&gt;");

            //Do a regex replace for Resources
            string regex = @"ResourceID=""(?<resid>.{36})"""; //Guids are always 36 characters long (including dashes)
            string linkReplacement = string.Format(@"ResourceID=""<Hyperlink NavigateUri=""/Resources/{0}/${{resid}}"" >${{resid}}</Hyperlink>""", config.PresentationID);
            stringToFormat = Regex.Replace(stringToFormat, regex, linkReplacement);

            stringToFormat = string.Format("<Paragraph>{0}</Paragraph>", stringToFormat);
            stringToFormat = string.Format("<Section xml:space=\"preserve\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">{0}</Section>", stringToFormat);

            InspectorBox.Xaml = stringToFormat;
        }

        private void DownloadSchemaButton_Click(object sender, System.Windows.RoutedEventArgs e) {
            PresentationConfig configToSave = CachedPresentationConfig;
            if(configToSave == null) {
                //Cannot save it if it han't been downloaded
                return;
            }

            SaveFileDialog saveDialog = new SaveFileDialog();
            saveDialog.DefaultExt = "xml";
            saveDialog.Filter = "XML Files|*.xml|All Files|*.*";
            if(saveDialog.ShowDialog() ?? false) {
                using(StreamWriter sw = new StreamWriter(saveDialog.OpenFile())){
                    sw.Write(CachedPresentationConfig.XML);
                }
            }

        }

        private void UploadSchemaButton_Click(object sender, System.Windows.RoutedEventArgs e) {
            OpenFileDialog openDialog = new OpenFileDialog();
            if(openDialog.ShowDialog() ?? false){
                using(StreamReader sr = new StreamReader(openDialog.File.OpenRead())) {
                    string schema = sr.ReadToEnd();
                    CachedPresentationConfig.XML = schema;
                    ctx.SubmitChanges();
                }
            }
        }

    }
}